#include "Microfono.h"

using std::cout;
using std::cerr;
using std::endl;

Microfono::Microfono():DispositivoAudio() {
	int ret;
	unsigned int val;
	Codificador = new Cod_Audio();
	Codificador->register_codecs();
	// Abro el dispositivo
	ret = snd_pcm_open(&this->handle, "hw", SND_PCM_STREAM_CAPTURE, 0);
	if(ret < 0) {
		cerr << "no se pudo abrir el dispositivo: " << snd_strerror(ret) << endl;
		exit(1);
	}
	// Pido memoria para los parametros
	snd_pcm_hw_params_alloca(&this->params);
	// Valores por defecto
	snd_pcm_hw_params_any(this->handle, this->params);
	// modo interleaved
	snd_pcm_hw_params_set_access(this->handle, this->params, SND_PCM_ACCESS_RW_INTERLEAVED);
	// Formato signed 16-bit little-endian
	snd_pcm_hw_params_set_format(this->handle, this->params, SND_PCM_FORMAT_S16_LE);
	// Seteo cantidad de canales
	snd_pcm_hw_params_set_channels(this->handle, this->params, this->canales);
	val = 44100;   // bits/segundo sampling rate (calidad CD)
	snd_pcm_hw_params_set_rate_near(this->handle, this->params, &val, &this->dir);
	snd_pcm_hw_params_set_period_size_near(this->handle, this->params, &this->frames, &this->dir);
	// Cargo los parametros al driver
	ret = snd_pcm_hw_params(this->handle, this->params);
	if(ret < 0) {
		cerr << "no se pudieron setear los parametros: " << snd_strerror(ret) << endl;
		exit(1);
	}
	// Tamanio del periodo
	snd_pcm_hw_params_get_period_size(this->params, &this->frames, &this->dir);

	Codificador->busca_encoder();

	Codificador->ini_contexto();

	Codificador->abre_encoder();

/*    snd_mixer_t *mixer;
    snd_mixer_elem_t *vol_ctl;
    snd_mixer_selem_id_t *volume_id;
    if(snd_mixer_open (&mixer, 0) < 0)
    	return 1;
    if(snd_mixer_attach (mixer, "default") < 0)
    	return 1;
    if(snd_mixer_selem_register (mixer, NULL, NULL) < 0)
    	return 1;
    if(snd_mixer_load (mixer) < 0)
    	return 1;
    snd_mixer_selem_id_alloca(&volume_id);
    snd_mixer_selem_id_set_name(volume_id, "PCM");
    snd_mixer_selem_id_set_name(volume_id, "Master");
    vol_ctl = snd_mixer_find_selem(mixer, volume_id);

    long min_vol, max_vol, dev_vol;
    if(snd_mixer_selem_get_capture_volume_range (vol_ctl, &min_vol,
  						 &max_vol) < 0)
    	return 1;

    dev_vol = 10 * (max_vol - min_vol) / 100 + min_vol;
    snd_mixer_selem_set_capture_volume_all(vol_ctl, 9);*/

}

void Microfono::ejecutar() {
	std::ofstream arch("salida.mp2");
	int ret, out_size;
	signed short* aux;   // Puntero auxiliar
	int faltan;   // Frames que faltan para completar un periodo
	uint8_t *frame_Codificado = NULL;
	while(1) {
		aux = this->buf;
		faltan = this->frames;
		while(faltan > 0) {
			ret = snd_pcm_readi(this->handle, aux, faltan);
            if(ret < 0) {
                if(this->recuperacion(ret) < 0) {
                    cerr << "microphone: Write error: " << snd_strerror(ret) << endl;
                    exit(EXIT_FAILURE);
                }
                break;   // Descarto el periodo
            }
			if(ret == -EPIPE) {
				// EPIPE = overrun
				cerr << "overrun occurred" << endl;
				snd_pcm_prepare(this->handle);
			}
			aux += ret * this->canales;
			faltan -= ret;
		}
		frame_Codificado = (uint8_t*)av_malloc(2 * 2 * Codificador->getFrameSize());
		out_size = Codificador->codificar(buf, sizeof(short) * this->buf_size, &frame_Codificado);
		arch.write((const char*)frame_Codificado, out_size);
		//write(STDOUT_FILENO, this->buf, sizeof(short) * this->buf_size);
		av_free(frame_Codificado);
	}
	snd_pcm_drain(this->handle);
	snd_pcm_close(this->handle);
	//snd_mixer_close(mixer);
}

Microfono::~Microfono() {
	delete Codificador;
}

